home *** CD-ROM | disk | FTP | other *** search
/ HPAVC / HPAVC CD-ROM.iso / pc / HPACK78S.ZIP / io / fastio.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-12-02  |  40.6 KB  |  1,510 lines

  1. /****************************************************************************
  2. *                                                                            *
  3. *                            HPACK Multi-System Archiver                        *
  4. *                            ===========================                        *
  5. *                                                                            *
  6. *                                Fast File I/O Routines                        *
  7. *                            FASTIO.C  Updated 10/07/92                        *
  8. *                                                                            *
  9. * This program is protected by copyright and as such any use or copying of    *
  10. *  this code for your own purposes directly or indirectly is highly uncool    *
  11. *                      and if you do so there will be....trubble.                *
  12. *                 And remember: We know where your kids go to school.            *
  13. *                                                                            *
  14. *        Copyright 1990 - 1992  Peter C.Gutmann.  All rights reserved        *
  15. *                                                                            *
  16. ****************************************************************************/
  17.  
  18. #include <stdlib.h>
  19. #include <string.h>
  20. #ifdef __MAC__
  21.   #include "defs.h"
  22.   #include "arcdir.h"
  23.   #include "error.h"
  24.   #include "flags.h"
  25.   #include "frontend.h"
  26.   #include "hpacklib.h"
  27.   #include "hpaktext.h"
  28.   #include "system.h"
  29.   #include "crc16.h"
  30.   #include "crypt.h"
  31.   #include "ebcdic.h"
  32.   #include "fastio.h"
  33.   #include "hpackio.h"
  34. #else
  35.   #include "defs.h"
  36.   #include "arcdir.h"
  37.   #include "error.h"
  38.   #include "flags.h"
  39.   #include "frontend.h"
  40.   #include "hpacklib.h"
  41.   #include "system.h"
  42.   #include "crc/crc16.h"
  43.   #include "crypt/crypt.h"
  44.   #include "data/ebcdic.h"
  45.   #include "io/fastio.h"
  46.   #include "io/hpackio.h"
  47.   #include "language/hpaktext.h"
  48. #endif /* __MAC__ */
  49.  
  50. /* Prototypes for functions in ARCHIVE.C */
  51.  
  52. void blankLine( int length );
  53.  
  54. #ifdef __MAC__
  55.  
  56. /* Prototypes for functions in MAC.C */
  57.  
  58. void bleuurgghh( void );
  59. void waitForDisk( void );
  60.  
  61. #endif /* __MAC__ */
  62.  
  63. /* Some vars used to keep track of the fast I/O routines.  OS's which support
  64.    asynchronous I/O can allocate a shadow buffer for independant reads/writes */
  65.  
  66. BYTE *_inBuffer, *_outBuffer;
  67. #if defined( __MSDOS__ )
  68.   WORD _inBufferBase, _outBufferBase;
  69. #endif /* __MSDOS__ */
  70. FD _inFD, _outFD;
  71. int _inByteCount, _outByteCount;
  72. int _inBytesRead;
  73.  
  74. /* Flags to control checksumming of input/output, the count of output bytes
  75.    to checksum, and the point in the buffer to start checksumming */
  76.  
  77. BOOLEAN doChecksumIn, doChecksumOut, doChecksumDirOut;
  78. long checksumLength;        /* Number of bytes to checksum */
  79. int checksumMark, dirChecksumMark;    /* Start point in buffers for checksumming data */
  80.  
  81. /* Flags to control encryption/decryption of input/output, the count of
  82.    output bytes to encrypt, and the point in the buffer to start encrypting */
  83.  
  84. BOOLEAN doCryptIn, doCryptOut;
  85. long cryptLength;            /* Number of bytes to decrypt */
  86. int cryptMark;                /* Start point in buffer for encrypting data */
  87.  
  88. /* Variables to handle the kludging of the skipping of checksumming of the
  89.    encryption header */
  90.  
  91. BOOLEAN preemptDecrypt;        /* Whether we need to preempt the checksumming */
  92. long preemptedChecksumLength;    /* Length of data to checksum */
  93.  
  94. /* The number of bytes written so far for this segment, the total number of
  95.    bytes written before this segment (needed for multipart archive writes),
  96.    and the current position in the archive (needed for multipart archive
  97.    reads) */
  98.  
  99. static long currLength, totalLength;
  100. static long currentPosition;
  101.  
  102. /* The output data intercept type */
  103.  
  104. static OUTINTERCEPT_TYPE outputIntercept = OUT_DATA;
  105.  
  106. /* Whether we need to pad the output data writtten to allow room for a
  107.    multipart archive trailer */
  108.  
  109. static BOOLEAN padOutput;
  110.  
  111. /* Prototypes for the output routines used by the output intercept code */
  112.  
  113. void initOutFormatText( void );
  114. void outFormatChar( const char ch );
  115. void endOutFormatText( void );            /* Formatted text output */
  116.  
  117. /* The value to use as line terminator when doing translation to MSDOS CRLF
  118.    format */
  119.  
  120. static BYTE lineEndChar;
  121.  
  122. /* Vars used to handle the general-purpose buffer.  This buffer is used
  123.    during extraction for textfile translation and during changes to an
  124.    archive for a general-purpose buffer for assembling data.  When necessary
  125.    the upper half of the mrglBuffer is sacred to the dirInfo handling code
  126.    for buffering of dirInfo */
  127.  
  128. #define DIRBUF_OFFSET    ( _BUFSIZE / 2 )    /* Start of dir.info buffer */
  129.  
  130. BYTE *mrglBuffer, *dirBuffer;
  131. int mrglBufCount, dirBufCount;
  132. int dirBytesRead;
  133.  
  134. /* Macro to output a byte to the mrglBuffer */
  135.  
  136. #define putMrglByte(ch)    do \
  137.                             { \
  138.                             if( mrglBufCount == _BUFSIZE ) \
  139.                                 writeMrglBuffer( _BUFSIZE ); \
  140.                             mrglBuffer[ mrglBufCount++ ] = ch; \
  141.                             } \
  142.                         while( 0 )
  143.  
  144. /* Defines to control the size of archive segments when creating a multipart
  145.    archive */
  146.  
  147. #define MULTIPART_TRAILER_SIZE    ( HPACK_ID_SIZE + sizeof( WORD ) + sizeof( BYTE ) )
  148. #define MIN_PARTSIZE            500        /* Min.data size for which we bother */
  149. #define MIN_ARCHIVE_SIZE        ( HPACK_ID_SIZE + MIN_PARTSIZE + MULTIPART_TRAILER_SIZE )
  150.  
  151. static int minPartSize;            /* The min.size of an archive segment */
  152. static BOOLEAN atomicWrite;        /* Whether we are in atomic write mode */
  153. BOOLEAN atomicWriteOK;            /* Whether the atomic write succeeded */
  154.  
  155. /****************************************************************************
  156. *                                                                            *
  157. *                            Initialize fast I/O functions                     *
  158. *                                                                            *
  159. ****************************************************************************/
  160.  
  161. /* Allocate buffers for the fast I/O routines, the GP buffer, and the shadow
  162.    buffers if used */
  163.  
  164. void initFastIO( void )
  165.     {
  166. #if defined( __MSDOS__ )
  167.     if( ( _inBuffer = ( BYTE * ) hmallocSeg( _BUFSIZE ) ) == NULL || \
  168.         ( _outBuffer = ( BYTE * ) hmallocSeg( _BUFSIZE ) ) == NULL || \
  169.         ( mrglBuffer = ( BYTE * ) hmalloc( _BUFSIZE ) ) == NULL )
  170. #else
  171.     if( ( _inBuffer = ( BYTE * ) hmalloc( _BUFSIZE ) ) == NULL || \
  172.         ( _outBuffer = ( BYTE * ) hmalloc( _BUFSIZE ) ) == NULL || \
  173.         ( mrglBuffer = ( BYTE * ) hmalloc( _BUFSIZE ) ) == NULL )
  174. #endif /* __MSDOS__ */
  175.         error( OUT_OF_MEMORY );
  176.     dirBuffer = mrglBuffer + DIRBUF_OFFSET;
  177.  
  178. #if defined( __MSDOS__ )
  179.     _inBufferBase = FP_SEG( _inBuffer );
  180.     _outBufferBase = FP_SEG( _outBuffer );
  181. #endif /* __MSDOS__ */
  182.  
  183.     /* Set up CRC16 lookup table */
  184.     initCRC16();
  185.     }
  186.  
  187. #if !defined( __MSDOS__ ) || defined( GUI )
  188.  
  189. /* Free the fast I/O buffers and the GP buffer */
  190.  
  191. void endFastIO( void )
  192.     {
  193.     sfree( _inBuffer, _BUFSIZE );
  194.     sfree( _outBuffer, _BUFSIZE );
  195.     sfree( mrglBuffer, _BUFSIZE );
  196.     }
  197. #endif /* !__MSDOS__ || GUI */
  198.  
  199. /* Reset input system */
  200.  
  201. void resetFastIn( void )
  202.     {
  203.     _inByteCount = 0;
  204.     doChecksumIn = doCryptIn = preemptDecrypt = FALSE;
  205.     cryptLength = checksumLength = 0L;
  206.     if( ( _inBytesRead = vread( _inBuffer, _BUFSIZE ) ) == ERROR )
  207.         fileError();
  208.     }
  209.  
  210. void resetFastOut( void )
  211.     {
  212.     _outByteCount = mrglBufCount = dirBufCount = 0;
  213.     currLength = totalLength = 0L;
  214.     doChecksumOut = doCryptOut = doChecksumDirOut = FALSE;
  215.     minPartSize = MIN_PARTSIZE;
  216.     atomicWrite = padOutput = FALSE;
  217.     }
  218.  
  219. #ifdef __MAC__
  220.  
  221. /* Save and restore the state of the output routines if they need to be used
  222.    for another output stream (used when writing to the resource fork file) */
  223.  
  224. static FD savedOutFD;
  225. static WORD savedMultipartFlags;
  226. static LONG savedCurrLength, savedTotalLength;
  227.  
  228. void saveOutputState( void )
  229.     {
  230.     /* Save output FD */
  231.     savedOutFD = getOutputFD();
  232.  
  233.     /* Save various output flags */
  234.     savedMultipartFlags = multipartFlags;
  235.     multipartFlags &= ~MULTIPART_WRITE;        /* Turn off multipart writes */
  236.     savedCurrLength = currLength;
  237.     savedTotalLength = totalLength;
  238.     }
  239.  
  240. void restoreOutputState( void )
  241.     {
  242.     /* Restore output FD */
  243.     setOutputFD( savedOutFD );
  244.  
  245.     /* Restore output flags */
  246.     multipartFlags = savedMultipartFlags;
  247.     currLength = savedCurrLength;
  248.     totalLength = savedTotalLength;
  249.     }
  250.  
  251. #endif /* __MAC__ */
  252.  
  253. /* Save and restore the state of the input routines in case we need to use
  254.    them for another input stream */
  255.  
  256. static FD savedInFD;
  257. static int savedInByteCount, savedInBytesRead;
  258. static BOOLEAN savedPreemptDecrypt;
  259. static WORD savedMultipartFlags;
  260. static LONG savedCurrentPosition;
  261.  
  262. void saveInputState( void )
  263.     {
  264.     /* Save input FD */
  265.     savedInFD = getInputFD();
  266.  
  267.     /* Save data in input buffer */
  268.     memcpy( mrglBuffer, _inBuffer, _BUFSIZE );
  269.     savedInByteCount = _inByteCount;
  270.     savedInBytesRead = _inBytesRead;
  271.     if( !( multipartFlags & MULTIPART_READ ) )
  272.         savedCurrentPosition = htell( savedInFD );
  273.     else
  274.         savedCurrentPosition = currentPosition;
  275.  
  276.     /* Save various input flags */
  277.     savedPreemptDecrypt = preemptDecrypt;
  278.     savedMultipartFlags = multipartFlags;
  279.     multipartFlags &= ~MULTIPART_READ;        /* Turn off multipart reads */
  280.     }
  281.  
  282. void restoreInputState( void )
  283.     {
  284.     /* Restore input FD */
  285.     setInputFD( savedInFD );
  286.  
  287.     /* Restore data to input buffer */
  288.     memcpy( _inBuffer, mrglBuffer, _BUFSIZE );
  289.     _inByteCount = savedInByteCount;
  290.     _inBytesRead = savedInBytesRead;
  291.     currentPosition = savedCurrentPosition;
  292.     if( !( multipartFlags & MULTIPART_READ ) )
  293.         hlseek( savedInFD, savedCurrentPosition, SEEK_SET );
  294.     else
  295.         vlseek( currentPosition, SEEK_SET );
  296.  
  297.     /* Restore various input flags */
  298.     preemptDecrypt = savedPreemptDecrypt;
  299.     multipartFlags = savedMultipartFlags;
  300.     }
  301.  
  302. inline void initTranslationSystem( const BYTE theChar )
  303.     {
  304.     /* Set up the line termination character */
  305.     lineEndChar = theChar;
  306.     }
  307.  
  308. /* Handle checksumming of input/output.  We use checksumBegin()/checksumEnd()
  309.    for output, and checksumSetInput() for input since the checksumming must
  310.    be done before decryption takes place, not afterwards */
  311.  
  312. /* Turn checksumming of output on/off */
  313.  
  314. void checksumBegin( const BOOLEAN resetChecksum )
  315.     {
  316.     doChecksumOut = TRUE;
  317.  
  318.     /* Reset checksum if necessary and mark start point in buffer */
  319.     if( resetChecksum )
  320.         crc16 = 0;
  321.     checksumMark = _outByteCount;
  322.     }
  323.  
  324. void checksumEnd( void )
  325.     {
  326.     if( doChecksumOut )
  327.         /* Checksum rest of data in outBuffer */
  328.         crc16buffer( _outBuffer + checksumMark, _outByteCount - checksumMark );
  329.  
  330.     doChecksumOut = FALSE;
  331.     }
  332.  
  333. void checksumSetInput( const long dataLength, const BOOLEAN resetChecksum )
  334.     {
  335.     int dataLeft = _BUFSIZE - _inByteCount;
  336.  
  337.     /* Reset the checksum value if necessary */
  338.     if( resetChecksum )
  339.         crc16 = 0;
  340.  
  341.     /* CRC any data already in the buffer at this point */
  342.     crc16buffer( _inBuffer + _inByteCount, ( dataLength < dataLeft ) ? \
  343.                                            ( int ) dataLength : dataLeft );
  344.     if( dataLength > dataLeft )
  345.         {
  346.         /* Calculate amount left to checksum and indicate that there is more */
  347.         checksumLength = dataLength - dataLeft;
  348.         doChecksumIn = TRUE;
  349.         }
  350.     }
  351.  
  352. /* Handle checksumming of the directory buffer output stream */
  353.  
  354. void checksumDirBegin( const BOOLEAN resetChecksum )
  355.     {
  356.     doChecksumDirOut = TRUE;
  357.  
  358.     /* Reset checksum if necessary and mark start point in buffer */
  359.     if( resetChecksum )
  360.         crc16 = 0;
  361.     dirChecksumMark = dirBufCount;
  362.     }
  363.  
  364. void checksumDirEnd( void )
  365.     {
  366.     if( doChecksumDirOut )
  367.         /* Checksum rest of data in outBuffer */
  368.         crc16buffer( dirBuffer + dirChecksumMark, dirBufCount - dirChecksumMark );
  369.  
  370.     doChecksumDirOut = FALSE;
  371.     }
  372.  
  373. /* Handle encryption of input/output, much as for checksumming */
  374.  
  375. int cryptBegin( const BOOLEAN isMainKey )
  376.     {
  377.     int cryptInfoLength;
  378.  
  379.     /* Write encryption information packet and initialise encryption system */
  380.     cryptInfoLength = putEncryptionInfo( isMainKey );
  381.     doCryptOut = TRUE;
  382.  
  383.     /* Mark start point in buffer */
  384.     cryptMark = _outByteCount;
  385.  
  386.     return( cryptInfoLength );
  387.     }
  388.  
  389. void cryptEnd( void )
  390.     {
  391.     if( doCryptOut )
  392.         /* Encrypt rest of data in outBuffer */
  393.         encryptCFB( _outBuffer + cryptMark, _outByteCount - cryptMark );
  394.  
  395.     doCryptOut = FALSE;
  396.     }
  397.  
  398. BOOLEAN cryptSetInput( long dataLength, int *cryptInfoLength )
  399.     {
  400.     int dataLeft;
  401.  
  402.     /* Read in encryption information packet and initialise encryption system */
  403.     if( !getEncryptionInfo( cryptInfoLength ) )
  404.         return( FALSE );
  405.  
  406.     dataLength -= *cryptInfoLength;
  407.     dataLeft = _BUFSIZE - _inByteCount;
  408.  
  409.     /* Perform any necessary checksumming */
  410.     if( preemptDecrypt )
  411.         {
  412.         checksumSetInput( preemptedChecksumLength - *cryptInfoLength, RESET_CHECKSUM );
  413.         preemptDecrypt = FALSE;
  414.         }
  415.  
  416.     /* Decrypt any data already in the buffer at this point */
  417.     decryptCFB( _inBuffer + _inByteCount, ( dataLength < dataLeft ) ? \
  418.                                           ( int ) dataLength : dataLeft );
  419.     if( dataLength > dataLeft )
  420.         {
  421.         /* Evaluate the number of bytes still left to decrypt and turn on the
  422.            decryptIn flag */
  423.         cryptLength = dataLength - dataLeft;
  424.         doCryptIn = TRUE;
  425.         }
  426.  
  427.     return( TRUE );
  428.     }
  429.  
  430. /* A kludge function which allows the checksumming of input data after the
  431.    encryption header has been skipped */
  432.  
  433. void preemptCryptChecksum( const long length )
  434.     {
  435.     preemptDecrypt = TRUE;
  436.     preemptedChecksumLength = length;
  437.     }
  438.  
  439. /* Get and set the current absolute position in the data */
  440.  
  441. long getCurrPosition( void )
  442.     {
  443.     return( totalLength + currLength + _outByteCount - HPACK_ID_SIZE );
  444.     }
  445.  
  446. void setCurrPosition( const long position )
  447.     {
  448.     currentPosition = position;
  449.     }
  450.  
  451. /* Turn atomic write mode on and off */
  452.  
  453. void setWriteType( const WRITE_TYPE writeType )
  454.     {
  455.     switch( writeType )
  456.         {
  457.         case STD_WRITE:
  458.             /* Set standard write mode */
  459.             minPartSize = MIN_PARTSIZE;
  460.             atomicWrite = padOutput = FALSE;
  461.             break;
  462.  
  463.         case ATOMIC_WRITE:
  464.             /* All data must be written onto same disk */
  465.             minPartSize = _outByteCount;
  466.  
  467.             atomicWrite = TRUE;
  468.             atomicWriteOK = FALSE;
  469.             padOutput = FALSE;
  470.             break;
  471.  
  472.         case SAFE_WRITE:
  473.             /* Pad the output data written to allow room for a multipart
  474.                archive trailer.  This is necessary for the end of the data
  475.                in a multipart archive, since after the next hwrite() we will
  476.                be leaving multipart-write mode so we need to ensure there is
  477.                always room for the trailer */
  478.             padOutput = TRUE;
  479.             break;
  480.         }
  481.     }
  482.  
  483. /****************************************************************************
  484. *                                                                            *
  485. *                            Data Fast I/O Functions                            *
  486. *                                                                            *
  487. ****************************************************************************/
  488.  
  489. /* Normally HPACK reads/writes values in big-endian format.  If there is
  490.    ever any need to change this to little-endian format, it can be done
  491.    here by defining RW_LITTLE_ENDIAN */
  492.  
  493. #if !defined( __MSDOS__ )
  494.  
  495. /* These should functions should really be implemented in assembly language
  496.    for efficiency */
  497.  
  498. #ifdef RW_LITTLE_ENDIAN
  499.  
  500. void fputLong( const LONG value )
  501.     {
  502.     fputByte( ( BYTE ) ( value & 0xFF ) );
  503.     fputByte( ( BYTE ) ( ( value >> 8 ) & 0xFF ) );
  504.     fputByte( ( BYTE ) ( ( value >> 16 ) & 0xFF ) );
  505.     fputByte( ( BYTE ) ( ( value >> 24 ) & 0xFF ) );
  506.     }
  507.  
  508. void fputWord( const WORD data )
  509.     {
  510.     fputByte( ( BYTE ) ( data & 0xFF ) );
  511.     fputByte( ( BYTE ) ( data >> BITS_PER_BYTE ) );
  512.     }
  513.  
  514. #else
  515.  
  516. void fputLong( const LONG value )
  517.     {
  518.     fputByte( ( BYTE ) ( ( value >> 24 ) & 0xFF ) );
  519.     fputByte( ( BYTE ) ( ( value >> 16 ) & 0xFF ) );
  520.     fputByte( ( BYTE ) ( ( value >> 8 ) & 0xFF ) );
  521.     fputByte( ( BYTE ) ( value & 0xFF ) );
  522.     }
  523.  
  524. void fputWord( const WORD data )
  525.     {
  526.     fputByte( ( BYTE ) ( data >> BITS_PER_BYTE ) );
  527.     fputByte( ( BYTE ) ( data & 0xFF ) );
  528.     }
  529.  
  530. #endif /* RW_LITTLE_ENDIAN */
  531.  
  532. void fputByte( const BYTE data )
  533.     {
  534.     /* Write the buffer if necessary */
  535.     if( _outByteCount == _BUFSIZE )
  536.         {
  537.         /* Encrypt the data if required */
  538.         if( doCryptOut )
  539.             {
  540.             encryptCFB( _outBuffer + cryptMark, _BUFSIZE - cryptMark );
  541.             cryptMark = 0;
  542.             }
  543.  
  544.         /* Checksum the data if required */
  545.         if( doChecksumOut )
  546.             {
  547.             crc16buffer( _outBuffer + checksumMark, _BUFSIZE - checksumMark );
  548.             checksumMark = 0;
  549.             }
  550.  
  551.         writeBuffer( _BUFSIZE );
  552.         }
  553.  
  554.     _outBuffer[ _outByteCount++ ] = data;
  555.     }
  556.  
  557. /* The function versions of getByte(), getWord(), and getLong() */
  558.  
  559. #ifdef RW_LITTLE_ENDIAN
  560.  
  561. LONG fgetLong( void )
  562.     {
  563.     LONG value;
  564.  
  565.     value = ( LONG ) fgetByte();
  566.     value |= ( LONG ) fgetByte() << 8;
  567.     value |= ( LONG ) fgetByte() << 16;
  568.     value |= ( LONG ) fgetByte() << 24;
  569.     return( value );
  570.     }
  571.  
  572. WORD fgetWord( void )
  573.     {
  574.     WORD value;
  575.  
  576.     value = ( WORD ) fgetByte();
  577.     value |= ( WORD ) fgetByte() << BITS_PER_BYTE;
  578.     return( value );
  579.     }
  580.  
  581. #else
  582.  
  583. LONG fgetLong( void )
  584.     {
  585.     LONG value;
  586.  
  587.     value = ( LONG ) fgetByte() << 24;
  588.     value |= ( LONG ) fgetByte() << 16;
  589.     value |= ( LONG ) fgetByte() << 8;
  590.     value |= ( LONG ) fgetByte();
  591.     return( value );
  592.     }
  593.  
  594. WORD fgetWord( void )
  595.     {
  596.     WORD value;
  597.  
  598.     value = ( WORD ) fgetByte() << BITS_PER_BYTE;
  599.     value |= ( WORD ) fgetByte();
  600.     return( value );
  601.     }
  602.  
  603. #endif /* RW_LITTLE_ENDIAN */
  604.  
  605. int fgetByte( void )
  606.     {
  607.     /* Refill the input buffer if necessary */
  608.     if( _inByteCount == _BUFSIZE )
  609.         {
  610.         /* Read in a new bufferful of data */
  611.         _inByteCount = 0;
  612.         if( ( _inBytesRead = vread( _inBuffer, _BUFSIZE ) ) == ERROR )
  613.             fileError();
  614.         }
  615.  
  616.     return( ( _inByteCount == _inBytesRead ) ? FEOF : _inBuffer[ _inByteCount++ ] );
  617.     }
  618.  
  619. /****************************************************************************
  620. *                                                                            *
  621. *                        Directory Data Fast I/O Functions                    *
  622. *                                                                            *
  623. ****************************************************************************/
  624.  
  625. /* Write data to the temporary directory data file.  These all write to the
  626.    directory data file so there is no need to specify a file descriptor.  We
  627.    can't use use fputByte(), fputWord(), or fputLong() for this since these
  628.    write to the outBuffer, so we use these versions which use the dirBuffer */
  629.  
  630. #ifdef RW_LITTLE_ENDIAN
  631.  
  632. void fputDirLong( const LONG data )
  633.     {
  634.     fputDirByte( ( BYTE ) ( data & 0xFF ) );
  635.     fputDirByte( ( BYTE ) ( ( data >> 8 ) & 0xFF ) );
  636.     fputDirByte( ( BYTE ) ( ( data >> 16 ) & 0xFF ) );
  637.     fputDirByte( ( BYTE ) ( ( data >> 24 ) & 0xFF ) );
  638.     }
  639.  
  640. void fputDirWord( const WORD data )
  641.     {
  642.     fputDirByte( ( BYTE ) ( data & 0xFF ) );
  643.     fputDirByte( ( BYTE ) ( data >> BITS_PER_BYTE ) );
  644.     }
  645.  
  646. #else
  647.  
  648. void fputDirLong( const LONG data )
  649.     {
  650.     fputDirByte( ( BYTE ) ( ( data >> 24 ) & 0xFF ) );
  651.     fputDirByte( ( BYTE ) ( ( data >> 16 ) & 0xFF ) );
  652.     fputDirByte( ( BYTE ) ( ( data >> 8 ) & 0xFF ) );
  653.     fputDirByte( ( BYTE ) ( data & 0xFF ) );
  654.     }
  655.  
  656. void fputDirWord( const WORD data )
  657.     {
  658.     fputDirByte( ( BYTE ) ( data >> BITS_PER_BYTE ) );
  659.     fputDirByte( ( BYTE ) ( data & 0xFF ) );
  660.     }
  661.  
  662. #endif /* RW_LITTLE_ENDIAN */
  663.  
  664. void fputDirByte( const BYTE data )
  665.     {
  666.     if( dirBufCount == DIRBUFSIZE )
  667.         writeDirBuffer( dirBufCount );
  668.     dirBuffer[ dirBufCount++ ] = data;
  669.     }
  670.  
  671. #endif /* !__MSDOS__ */
  672.  
  673. /****************************************************************************
  674. *                                                                            *
  675. *                            Memory Fast I/O Functions                            *
  676. *                                                                            *
  677. ****************************************************************************/
  678.  
  679. /* Get or put WORD's and LONG's from and to memory */
  680.  
  681. #if !defined( __MSDOS__ )
  682.  
  683. /* The memory equivalents of fgetWord() and fgetLong() */
  684.  
  685. #ifdef RW_LITTLE_ENDIAN
  686.  
  687. void mputLong( BYTE *memPtr, const LONG data )
  688.     {
  689.     memPtr[ 0 ] = ( BYTE ) ( data & 0xFF );
  690.     memPtr[ 1 ] = ( BYTE ) ( ( data >> 8 ) & 0xFF );
  691.     memPtr[ 2 ] = ( BYTE ) ( ( data >> 16 ) & 0xFF );
  692.     memPtr[ 3 ] = ( BYTE ) ( ( data >> 24 ) & 0xFF );
  693.     }
  694.  
  695. void mputWord( BYTE *memPtr, const WORD data )
  696.     {
  697.     memPtr[ 0 ] = ( BYTE ) ( data & 0xFF );
  698.     memPtr[ 1 ] = ( BYTE ) ( ( data >> 8 ) & 0xFF );
  699.     }
  700.  
  701. #else
  702.  
  703. void mputLong( BYTE *memPtr, const LONG data )
  704.     {
  705.     memPtr[ 0 ] = ( BYTE ) ( ( data >> 24 ) & 0xFF );
  706.     memPtr[ 1 ] = ( BYTE ) ( ( data >> 16 ) & 0xFF );
  707.     memPtr[ 2 ] = ( BYTE ) ( ( data >> 8 ) & 0xFF );
  708.     memPtr[ 3 ] = ( BYTE ) ( data & 0xFF );
  709.     }
  710.  
  711. void mputWord( BYTE *memPtr, const WORD data )
  712.     {
  713.     memPtr[ 0 ] = ( BYTE ) ( ( data >> 8 ) & 0xFF );
  714.     memPtr[ 1 ] = ( BYTE ) ( data & 0xFF );
  715.     }
  716.  
  717. #endif /* RW_LITTLE_ENDIAN */
  718.  
  719. /* The memory equivalents of fgetWord() and fgetLong() */
  720.  
  721. #ifdef RW_LITTLE_ENDIAN
  722.  
  723. LONG mgetLong( BYTE *memPtr )
  724.     {
  725.     return( ( LONG ) memPtr[ 0 ] | \
  726.             ( ( LONG ) memPtr[ 1 ] << 8 ) | \
  727.             ( ( LONG ) memPtr[ 2 ] << 16 ) | \
  728.             ( ( LONG ) memPtr[ 3 ] << 24 ) );
  729.     }
  730.  
  731. WORD mgetWord( BYTE *memPtr )
  732.     {
  733.     return( ( WORD ) memPtr[ 0 ] | ( ( WORD ) memPtr[ 1 ] << 8 ) );
  734.     }
  735.  
  736. #else
  737.  
  738. LONG mgetLong( BYTE *memPtr )
  739.     {
  740.     return( ( ( LONG ) memPtr[ 0 ] << 24 ) | \
  741.             ( ( LONG ) memPtr[ 1 ] << 16 ) | \
  742.             ( ( LONG ) memPtr[ 2 ] << 8 ) | \
  743.             ( LONG ) memPtr[ 3 ] );
  744.     }
  745.  
  746. WORD mgetWord( BYTE *memPtr )
  747.     {
  748.     return( ( ( WORD ) memPtr[ 0 ] << 8 ) | ( WORD ) memPtr[ 1 ] );
  749.     }
  750.  
  751. #endif /* RW_LITTLE_ENDIAN */
  752.  
  753. #endif /* !__MSDOS__ */
  754.  
  755. /****************************************************************************
  756. *                                                                            *
  757. *                            Fast I/O Support Functions                        *
  758. *                                                                            *
  759. ****************************************************************************/
  760.  
  761. #ifndef GUI
  762.  
  763. /* Wait for the luser to continue when handling a multipart archive */
  764.  
  765. void multipartWait( const WORD promptType, const int partNo )
  766.     {
  767. #ifdef __MAC__
  768.     bleuurgghh();
  769. #endif /* __MAC__ */
  770.  
  771.     if( promptType & WAIT_PARTNO )
  772.         hprintf( MESG_PART_d_OF_MULTIPART_ARCHIVE, partNo + 1 );
  773.     else
  774.         hputchar( '\n' );
  775.     hprintf( MESG_PLEASE_INSERT_THE );
  776.     if( promptType & WAIT_NEXTDISK )
  777.         hprintf( MESG_NEXT_DISK );
  778.     else
  779.         if( promptType & WAIT_PREVDISK )
  780.             hprintf( MESG_PREV_DISK );
  781.         else
  782.             {
  783.             hprintf( MESG_DISK_CONTAINING );
  784.             if( promptType & WAIT_LASTPART )
  785.                 hprintf( MESG_THE_LAST_PART );
  786.             else
  787.                 hprintf( MESG_PART_d, partNo + 1 );
  788.             hprintf( MESG_OF_THIS_ARCHIVE );
  789.             }
  790. #ifdef __MAC__
  791.     waitForDisk();
  792. #else
  793.     hprintf( MESG_AND_PRESS_A_KEY );
  794.     hgetch();
  795. #endif /* __MAC__ */
  796.     blankLine( screenWidth - 1 );    /* Blank out prompt message */
  797.     if( promptType & WAIT_NEXTDISK )
  798.         hprintf( MESG_CONTINUING );
  799.     }
  800. #endif /* GUI */
  801.  
  802. /* Skip ahead a certain number of bytes.  Doing this as a direct hlseek() is
  803.    not possible since some of the data may already be in the buffer or may be
  804.    on a different disk */
  805.  
  806. void skipSeek( LONG skipLength )
  807.     {
  808.     int bytesInBuffer = _inBytesRead - _inByteCount;
  809.     LONG count;
  810.  
  811.     if( doCryptIn )
  812.         if( cryptLength > skipLength )
  813.             {
  814.             /* If there is more encrypted data left after the data we are
  815.                skipping over, we have to read in all the data we would
  816.                normally seek over for decryption purposes */
  817.             cryptLength -= skipLength;
  818.             for( count = 0; count < skipLength; count++ )
  819.                 fgetByte();
  820.             return;
  821.             }
  822.         else
  823.             /* We've exhausted the encrypted data */
  824.             cryptLength = 0;
  825.  
  826.     if( skipLength < bytesInBuffer )
  827.         /* We can satisfy the request with what is still in the buffer */
  828.         _inByteCount += ( WORD ) skipLength;
  829.     else
  830.         {
  831.         /* First use all the bytes still in the buffer */
  832.         skipLength -= bytesInBuffer;
  833.  
  834.         /* Now we can do an hlseek() if necessary */
  835.         if( skipLength )
  836.             /* Check if we can satisfy the seek request in the current
  837.                archive part */
  838.             if( !( flags & MULTIPART_READ ) || \
  839.                 currPart == getPartNumber( skipLength ) )
  840.                 hlseek( _inFD, skipLength, SEEK_CUR );
  841.             else
  842.                 /* Seek destination is outside the current archive section,
  843.                    do a full vlseek() */
  844.                 vlseek( skipLength, SEEK_CUR );
  845.  
  846.         /* Force a read at the next getByte() */
  847.         forceRead();
  848.         }
  849.     }
  850.  
  851. /* Skip to the next piece of input data */
  852.  
  853. void skipToData( void )
  854.     {
  855.     if( skipDist )
  856.         {
  857.         /* Move past unwanted data and reset skip distance */
  858.         skipSeek( skipDist );
  859.         skipDist = 0L;
  860.         }
  861.     }
  862.  
  863. /* Set the output intercept */
  864.  
  865. void setOutputIntercept( OUTINTERCEPT_TYPE interceptType )
  866.     {
  867.     outputIntercept = interceptType;
  868.  
  869.     switch( outputIntercept )
  870.         {
  871.         case OUT_FMT_TEXT:
  872.             /* Formatted text output */
  873.             initOutFormatText();
  874.             break;
  875.  
  876.         default:
  877.             /* Default: No action */
  878.             ;
  879.         }
  880.     }
  881.  
  882. /* Reset the output intercept to the default setting */
  883.  
  884. void resetOutputIntercept( void )
  885.     {
  886.     switch( outputIntercept )
  887.         {
  888.         case OUT_FMT_TEXT:
  889.             /* Formatted text output */
  890.             endOutFormatText();
  891.             break;
  892.  
  893.         default:
  894.             /* Default: No action */
  895.             ;
  896.         }
  897.  
  898.     /* Reset output intercept to default type */
  899.     outputIntercept = OUT_DATA;
  900.     }
  901.  
  902. /* Perform a seek, moving over multiple disks if necessary */
  903.  
  904. long vlseek( const long offset, const int whence )
  905.     {
  906.     long position = offset;        /* Default is SEEK_SET */
  907.     int thePart;
  908.  
  909.     /* Do a quick check for whether we can do a normal seek */
  910.     if( !( multipartFlags & MULTIPART_READ ) )
  911.         {
  912.         /* Adjust for virtual start of archive if necessary */
  913.         if( whence == SEEK_SET )
  914.             position += HPACK_ID_SIZE;
  915.  
  916.         return( hlseek( _inFD, position, whence ) );
  917.         }
  918.  
  919.     /* Turn all seeks into an absolute seek */
  920.     switch( whence )
  921.         {
  922.         case SEEK_CUR:
  923.             /* Seek relative to current position */
  924.             position += currentPosition;
  925.             break;
  926.  
  927.         case SEEK_END:
  928.             /* Seek relative to end of archive */
  929.             position += endPosition;
  930.         }
  931.  
  932.     /* Sanity check in case the offset info is from a corrupt archive - don't
  933.        try to move to nonexistant archive segment */
  934.     if( position < 0L )
  935.         return( position );
  936.  
  937.     /* Get the disk the correct part of the archive is on if necessary,
  938.        then move to the offset in that segment */
  939.     if( ( thePart = getPartNumber( position ) ) != currPart )
  940.         getPart( thePart );
  941.     if( thePart )
  942.         hlseek( _inFD, ( position - getPartSize( thePart - 1 ) ) + HPACK_ID_SIZE, SEEK_SET );
  943.     else
  944.         hlseek( _inFD, position + HPACK_ID_SIZE, SEEK_SET );
  945.     currentPosition = position;
  946.  
  947.     /* Update count of bytes left to read */
  948.     segmentEnd = getPartSize( thePart ) - currentPosition;
  949.  
  950.     return( position );
  951.     }
  952.  
  953. /* Return the current position, taking multi-disk archives into account */
  954.  
  955. long vtell( void )
  956.     {
  957.     /* Do a quick check for whether we can do a normal seek */
  958.     if( !( multipartFlags & MULTIPART_READ ) )
  959.         return( htell( _inFD ) );
  960.  
  961.     /* Return the current position in the archive */
  962.     return( currentPosition );
  963.     }
  964.  
  965. /* Read in a bufferful of data, skipping to the next disk in the case of a
  966.    multipart archive */
  967.  
  968. int vread( BYTE *buffer, int bufSize )
  969.     {
  970.     int startOffset = 0;    /* Remember start position of read */
  971.     int bytesRead = 0, retVal;
  972.  
  973.     /* Do a quick check for whether we can do a normal read */
  974.     if( !( multipartFlags & MULTIPART_READ ) )
  975.         {
  976.         if( ( bytesRead = hread( _inFD, buffer, bufSize ) ) == IO_ERROR )
  977.             fileError();
  978.         }
  979.     else
  980.         {
  981.         /* Perform a read, checking for end of data */
  982. retryRead:
  983.         if( segmentEnd > bufSize )
  984.             {
  985.             if( ( retVal = hread( _inFD, buffer + startOffset, bufSize ) ) == IO_ERROR )
  986.                 fileError();
  987.             bytesRead += retVal;
  988.             segmentEnd -= bufSize;
  989.             }
  990.         else
  991.             {
  992.             /* Read in what's left into the buffer */
  993.             if( segmentEnd )
  994.                 {
  995.                 if( hread( _inFD, buffer + startOffset, ( int ) segmentEnd ) == IO_ERROR )
  996.                     fileError();
  997.                 startOffset += ( int ) segmentEnd;
  998.                 bufSize -= ( int ) segmentEnd;
  999.                 bytesRead += ( int ) segmentEnd;
  1000.                 }
  1001.  
  1002.             /* More parts to go, get the next disk */
  1003.             if( currPart < lastPart )
  1004.                 {
  1005.                 currPart++;
  1006.                 getPart( currPart );
  1007.                 segmentEnd = getPartSize( currPart ) - getPartSize( currPart - 1 ) ;
  1008.  
  1009.                 /* Read in the rest of _inBuffer */
  1010.                 hlseek( _inFD, HPACK_ID_SIZE, SEEK_SET );
  1011.                 goto retryRead;
  1012.                 }
  1013.             }
  1014.         }
  1015.  
  1016.     /* Checksum the data if required */
  1017.     if( doChecksumIn )
  1018.         {
  1019.         crc16buffer( _inBuffer, ( bufSize < checksumLength ) ? bufSize : ( int ) checksumLength );
  1020.         if( bufSize < checksumLength )
  1021.             checksumLength -= bufSize;
  1022.         else
  1023.             {
  1024.             checksumLength = 0;
  1025.             doChecksumIn = FALSE;
  1026.             }
  1027.         }
  1028.  
  1029.     /* Decrypt the data if necessary */
  1030.     if( doCryptIn )
  1031.         {
  1032.         decryptCFB( _inBuffer, ( bufSize < cryptLength ) ? bufSize : ( int ) cryptLength );
  1033.         if( bufSize < cryptLength )
  1034.             cryptLength -= bufSize;
  1035.         else
  1036.             {
  1037.             cryptLength = 0;
  1038.             doCryptIn = FALSE;
  1039.             }
  1040.         }
  1041.  
  1042.     /* Update position in archive */
  1043.     currentPosition += bytesRead;
  1044.  
  1045.     return( bytesRead );
  1046.     }
  1047.  
  1048. /* Write out a certain amount of data.  This is a special version which checks
  1049.    for the disk being full by making sure the no.of bytes written are the same
  1050.    as the number of bytes requested to be written (as well as the normal
  1051.    ERROR return value, since hwrite() does not treat disk full as an ERROR),
  1052.    and also handles multi-part archives by asking for another disk.
  1053.  
  1054.    Note that once a write fails in a multipart archive we don't need to bother
  1055.    retrying the write on the new disk since we've already cleared some of the
  1056.    buffer on the current disk and a write will be forced as soon as the buffer
  1057.    is full again anyway.  The only problem this causes is that writeBuffer()
  1058.    may need to be called multiple times if the buffer is being flushed.
  1059.  
  1060.    0 = Head in free space
  1061.    1 = Head placed firmly against wall
  1062.  
  1063.    Multidisk archives = 10101010101010101010101010 */
  1064.  
  1065. BOOLEAN outputAdjusted;
  1066.  
  1067. void vwrite( BYTE *buffer, int bufSize )
  1068.     {
  1069.     int i, bytesWritten;
  1070.     BOOLEAN retryWrite = FALSE;
  1071.  
  1072.     if( outputIntercept == OUT_FMT_TEXT )
  1073.         {
  1074.         /* Formatted text output */
  1075.         for( i = 0; i < bufSize; i++ )
  1076.             outFormatChar( buffer[ i ] );
  1077.         }
  1078.  
  1079.     /* If we're done with the data, leave now */
  1080.     if( outputIntercept != OUT_DATA )
  1081.         return;
  1082.  
  1083.     /* Output raw data to FD */
  1084.     if( ( bytesWritten = hwrite( _outFD, buffer, bufSize ) ) == ERROR )
  1085.         fileError();
  1086.  
  1087.     /* Now update the count of bytes written unless we're writing the final
  1088.        info on a multipart archive.  Note that this does not include the
  1089.        header or trailer information, only the raw data */
  1090.     if( !atomicWrite )
  1091.         currLength += bytesWritten;
  1092. #ifdef __MSDOS__
  1093.     /* Wonderful things to tell your kids #27: The check for the identity of
  1094.        _outFD is necessary under MSDOS since there is a ^Z (CPM EOF) on the
  1095.        end of the file which is not written, and which ends up causing an
  1096.        "Out of disk space" error on STDOUT if it isn't caught */
  1097.     if( ( bytesWritten != bufSize ) && ( _outFD > STDPRN ) )
  1098. #else
  1099.     if( bytesWritten != bufSize )
  1100. #endif /* __MSDOS__ */
  1101.         {
  1102.         /* Complain if its not a multidisk archive and we run out of disk
  1103.            space.  Note that once we've locked the disk space by writing as
  1104.            much as possible we don't need to check space availability or the
  1105.            return status of hwrite() any more since the disk space has already
  1106.            been allocated/written to */
  1107.         if( !( multipartFlags & MULTIPART_WRITE ) )
  1108.             error( OUT_OF_DISK_SPACE );
  1109.  
  1110.         /* Check whether the archive is big enough to make it worthwhile */
  1111.         currLength -= HPACK_ID_SIZE + MULTIPART_TRAILER_SIZE;
  1112.                     /* Don't count info at start and end */
  1113.         i = 0;
  1114.         if( currLength > minPartSize )
  1115.             {
  1116.             /* Check if there's enough room to append the trailer information */
  1117.             if( bytesWritten < MULTIPART_TRAILER_SIZE )
  1118.                 {
  1119.                 if( atomicWrite )
  1120.                     {
  1121.                     /* Since we wrote the previous block in SAFE_WRITE mode,
  1122.                        we know there is enough room for the trailer, so we
  1123.                        just seek back and add it */
  1124.                     hlseek( archiveFD, -( LONG ) MULTIPART_TRAILER_SIZE, SEEK_END );
  1125.                     htruncate( archiveFD );
  1126.                     }
  1127.                 else
  1128.                     {
  1129.                     /* Not enough room to append trailer information, backtrack
  1130.                        and read in data at end of archive which is about to be
  1131.                        overwritten */
  1132.                     i = MULTIPART_TRAILER_SIZE - bytesWritten;
  1133.                     hlseek( archiveFD, -( LONG ) MULTIPART_TRAILER_SIZE, SEEK_END );
  1134.                     hread( archiveFD, mrglBuffer + HPACK_ID_SIZE, i );
  1135.  
  1136.                     /* Move data which will be overwritten by the trailer info.
  1137.                        into mrglBuffer as well */
  1138.                     memcpy( mrglBuffer + HPACK_ID_SIZE + i, _outBuffer, MULTIPART_TRAILER_SIZE );
  1139.                     i += MULTIPART_TRAILER_SIZE;
  1140.                     bytesWritten = MULTIPART_TRAILER_SIZE;
  1141.                     }
  1142.                 }
  1143.             else
  1144.                 /* Under most OS's this is the only case which will ever occur
  1145.                    since writes are rounded to the disk sector size */
  1146.                 if( atomicWrite )
  1147.                     {
  1148.                     /* We need to get everything on one disk, go back and zap
  1149.                        anything we've written (including the previously-written
  1150.                        padding bytes) */
  1151.                     bytesWritten += MULTIPART_TRAILER_SIZE;
  1152.                     hlseek( archiveFD, -( LONG ) bytesWritten, SEEK_END );
  1153.                     htruncate( archiveFD );
  1154.                     }
  1155.                 else
  1156.                     /* Just go back a bit and add the trailer */
  1157.                     bytesWritten -= MULTIPART_TRAILER_SIZE;
  1158.  
  1159.             if( atomicWrite )
  1160.                 {
  1161.                 /* Save output buffer info for later */
  1162.                 memcpy( mrglBuffer, _outBuffer, MULTIPART_TRAILER_SIZE );
  1163.                 bytesWritten = _outByteCount;
  1164.                 _outByteCount = 0;
  1165.                 }
  1166.             else
  1167.                 /* Backtrack MULTIPART_TRAILER_SIZE bytes if necessary */
  1168.                 hlseek( archiveFD, -( LONG ) MULTIPART_TRAILER_SIZE, SEEK_END );
  1169.  
  1170.             /* Append trailer information */
  1171.             fputWord( currPart++ );
  1172.             fputByte( SPECIAL_MULTIPART );
  1173.             fputByte( HPACK_ID[ 0 ] );
  1174.             fputByte( HPACK_ID[ 1 ] );
  1175.             fputByte( HPACK_ID[ 2 ] );
  1176.             fputByte( HPACK_ID[ 3 ] );
  1177.             hwrite( archiveFD, _outBuffer, MULTIPART_TRAILER_SIZE );
  1178.             hclose( archiveFD );
  1179.             if( atomicWrite )
  1180.                 {
  1181.                 /* Restore output buffer info and retry on another disk */
  1182.                 memcpy( _outBuffer, mrglBuffer, MULTIPART_TRAILER_SIZE );
  1183.                 _outByteCount = bytesWritten;
  1184.                 retryWrite = TRUE;    /* Retry write later on */
  1185.                 }
  1186.             else
  1187.                 {
  1188.                 _outByteCount = 0;    /* Reset count from fput()'s */
  1189.                 addPartSize( totalLength + currLength );
  1190.                 lastPart++;
  1191.                 }
  1192.             }
  1193.         else
  1194.             {
  1195.             /* Archive is too short to bother with, delete it */
  1196.             if( currLength > bytesWritten )
  1197.                 {
  1198.                 /* Read back data already written */
  1199.                 currLength -= bytesWritten;        /* Don't reread data in _outBuf */
  1200.                 currLength += MULTIPART_TRAILER_SIZE;    /* Adj.len.to proper size */
  1201.                 i = ( int ) currLength;
  1202.                 hlseek( archiveFD, HPACK_ID_SIZE, SEEK_SET );
  1203.                 hread( archiveFD, mrglBuffer + HPACK_ID_SIZE, i );
  1204.                 }
  1205.             bytesWritten = 0;
  1206.             hclose( archiveFD );
  1207.             hunlink( errorFileName );
  1208.             errorFD = 0;    /* No need to delete arch.on err.any more */
  1209. #ifdef GUI
  1210.             alert( ALERT_ARCH_SECTION_TOO_SHORT, NULL );
  1211. #else
  1212.             hprintf( WARN_ARCHIVE_SECTION_TOO_SHORT );
  1213. #endif /* GUI */
  1214.             }
  1215.  
  1216.         /* Go to next disk */
  1217.         multipartWait( WAIT_NEXTDISK, 0 );
  1218.         if( !( flags & OVERWRITE_SRC ) && \
  1219.             ( archiveFD = hopen( errorFileName, O_RDONLY ) ) != ERROR )
  1220.             {
  1221.             /* Make sure we don't overwrite an existing archive unless explicity
  1222.                asked to */
  1223.             hclose( archiveFD );
  1224.             error( CANNOT_OPEN_ARCHFILE, errorFileName );
  1225.             }
  1226.         if( ( errorFD = archiveFD = hcreat( errorFileName, CREAT_ATTR ) ) == ERROR )
  1227.             error( CANNOT_OPEN_ARCHFILE, errorFileName );
  1228.         setOutputFD( archiveFD );
  1229.  
  1230.         /* If we need to retry the write later on, add the header for a new
  1231.            archive and exit now */
  1232.         if( retryWrite )
  1233.             {
  1234.             memmove( _outBuffer + HPACK_ID_SIZE, _outBuffer, _outByteCount );
  1235.             memcpy( _outBuffer, HPACK_ID, HPACK_ID_SIZE );
  1236.             return;
  1237.             }
  1238.  
  1239.         /* Try and write out the number of bytes we need for a minimum-size archive */
  1240.         memcpy( mrglBuffer, HPACK_ID, HPACK_ID_SIZE );
  1241.         i += HPACK_ID_SIZE;
  1242.         while( hwrite( archiveFD, mrglBuffer, MIN_ARCHIVE_SIZE ) < MIN_ARCHIVE_SIZE )
  1243.             {
  1244.             hclose( archiveFD );
  1245.             hunlink( errorFileName );
  1246.             errorFD = 0;
  1247. #ifdef GUI
  1248.             alert( ALERT_ARCH_SECTION_TOO_SHORT, NULL );
  1249. #else
  1250.             hprintf( WARN_ARCHIVE_SECTION_TOO_SHORT );
  1251. #endif /* GUI */
  1252.             multipartWait( WAIT_NEXTDISK, 0 );
  1253.             if( !( flags & OVERWRITE_SRC ) && \
  1254.                 ( archiveFD = hopen( errorFileName, O_RDONLY ) ) != ERROR )
  1255.                 {
  1256.                 /* Make sure we don't overwrite an existing archive unless
  1257.                    explicity asked to */
  1258.                 hclose( archiveFD );
  1259.                 error( CANNOT_OPEN_ARCHFILE, errorFileName );
  1260.                 }
  1261.             if( ( errorFD = archiveFD = hcreat( errorFileName, CREAT_ATTR ) ) == ERROR )
  1262.                 error( CANNOT_OPEN_ARCHFILE, errorFileName );
  1263.             setOutputFD( archiveFD );
  1264.             }
  1265.         hlseek( archiveFD, i, SEEK_SET );    /* Seek back to last valid byte */
  1266.         totalLength += currLength;    /* Add new segment size */
  1267.         currLength = ( LONG ) i;
  1268.  
  1269.         /* Now we have room for an archive of at least MIN_ARCHIVE_SIZE bytes
  1270.            as well as having written out any backread data.  Move data down
  1271.            to start of _outBuffer if necessary and adjust the new start position
  1272.            of data in the buffer */
  1273.         if( padOutput )        /* !!! Don't write it on *last* write !!! */
  1274.             {
  1275.             bufSize -= MULTIPART_TRAILER_SIZE;    /* Don't write padding */
  1276.             outputAdjusted = TRUE;
  1277.             }
  1278.         if( bytesWritten )
  1279.             memcpy( _outBuffer, _outBuffer + bytesWritten, bufSize - bytesWritten );
  1280.         bufSize -= bytesWritten;
  1281.         checksumMark = _outByteCount = bufSize;
  1282.         }
  1283.  
  1284.     /* If we got this far, the atomic write succeeded */
  1285.     if( atomicWrite )
  1286.         atomicWriteOK = TRUE;
  1287.     }
  1288.  
  1289. /* High-level writeBuffer() routine with character set translation */
  1290.  
  1291. #define DC1        ( 0x11 ^ 0x80 )    /* Prime ASCII run count escape code in
  1292.                                    high-bit set format */
  1293. #define CPM_EOF    0x1A            /* ^Z which turns up in some MSDOS files */
  1294.  
  1295. void writeBuffer( const int bufSize )
  1296.     {
  1297.     static BOOLEAN isRunCount = FALSE;
  1298. #if !defined( __ATARI__ ) && !defined( __MSDOS__ ) && !defined( __OS2__ )
  1299.     static BOOLEAN crSeen = FALSE;
  1300. #endif /* !( __ATARI__ || __MSDOS__ || __OS2__ ) */
  1301.     BYTE ch;
  1302.  
  1303.     /* Reset output byte counter unless we need to remember the number of
  1304.        output bytes for backtracking purposes */
  1305.     if( !atomicWrite )
  1306.         _outByteCount = 0;
  1307.  
  1308.     /* We may have more work to do if we are using output translation.
  1309.        The order of translation is to translate char sets, then translate
  1310.        EOF chars */
  1311.     if( flags & XLATE_OUTPUT )
  1312.         {
  1313.         if( xlateFlags & XLATE_PRIME )
  1314.             {
  1315.             /* Translate buffer from Prime ASCII -> normal ASCII */
  1316.             while( _outByteCount < bufSize )
  1317.                 {
  1318.                 /* Get char, treat as run count if necessary */
  1319.                 ch = _outBuffer[ _outByteCount++ ];
  1320.                 if( isRunCount )
  1321.                     {
  1322.                     /* Output RLE'd spaces */
  1323.                     while( ch-- )
  1324.                         putMrglByte( ' ' );
  1325.                     isRunCount = FALSE;
  1326.                     continue;
  1327.                     }
  1328.  
  1329.                 /* Don't output special chars */
  1330.                 if( ch == DC1 || !ch )
  1331.                     {
  1332.                     isRunCount = ( ch == DC1 );
  1333.                     continue;
  1334.                     }
  1335.  
  1336.                 /* Output char with high bits toggled; if it's a NL, prepend
  1337.                    a CR */
  1338.                 if( ( ch ^ 0x80 ) == '\n' )
  1339.                     putMrglByte( '\r' );
  1340.                 putMrglByte( ch ^ 0x80 );
  1341.                 }
  1342.  
  1343.             _outByteCount = 0;        /* Re-reset byte counter */
  1344.             return;                    /* Leave now */
  1345.             }
  1346.         else
  1347.             {
  1348.             if( xlateFlags & XLATE_EBCDIC )
  1349.                 /* Translate buffer from EBCDIC -> ASCII */
  1350.                 while( _outByteCount < bufSize )
  1351.                     {
  1352.                     _outBuffer[ _outByteCount ] = xlateTbl[ _outBuffer[ _outByteCount ] ];
  1353.                     _outByteCount++;    /* Can't do above - used on LHS and RHS */
  1354.                     }
  1355.  
  1356.             _outByteCount = 0;        /* Reset byte counter */
  1357.  
  1358.             if( xlateFlags & XLATE_EOL )
  1359.                 {
  1360.                 /* Perform EOL translation */
  1361.                 while( _outByteCount < bufSize )
  1362.                     {
  1363.                     /* Check whether we need to translate this char */
  1364. #if defined( __ATARI__ ) || defined( __MSDOS__ ) || defined( __OS2__ )
  1365.                     if( ( ch = _outBuffer[ _outByteCount++ ] ) == lineEndChar )
  1366.                         {
  1367.                         /* Output CRLF in place of existing line terminator */
  1368.                         putMrglByte( '\r' );
  1369.                         putMrglByte( '\n' );
  1370.                         }
  1371. #else
  1372.                     if( ( ch = _outBuffer[ _outByteCount++ ] ) == ( lineEndChar & 0x7F ) || \
  1373.                         ( crSeen && ch == '\n' ) )
  1374.                         {
  1375.                         /* Check for CR of CRLF pair if necessary */
  1376.                         if( ( lineEndChar & 0x80 ) && ch == '\r' )
  1377.                             {
  1378.                             /* Seen CR of CRLF pair */
  1379.                             crSeen = TRUE;
  1380.                             continue;
  1381.                             }
  1382.  
  1383.                         if( !crSeen || ( crSeen && ch == '\n' ) )
  1384.                             /* See either CR alone, LF alone, or CRLF */
  1385.   #if defined( __AMIGA__ ) || defined( __ARC__ ) || defined( __UNIX__ )
  1386.                             putMrglByte( '\n' );
  1387.   #elif defined( __MAC__ )
  1388.                             putMrglByte( '\r' );
  1389.   #endif /* Various OS-specific defines */
  1390.                         else
  1391.                             /* Must have been a spurious CR-only */
  1392.                             if( ch != CPM_EOF )
  1393.                                 putMrglByte( ch );
  1394.                         crSeen = FALSE;
  1395.                         }
  1396. #endif /* __ATARI__ || __MSDOS__ || __OS2__ */
  1397.                     else
  1398.                         /* Copy the value across directly */
  1399.                         if( ch != CPM_EOF )
  1400.                             putMrglByte( ch );
  1401.                     }
  1402.  
  1403.                 _outByteCount = 0;        /* Re-reset byte counter */
  1404.                 return;                    /* Leave now */
  1405.                 }
  1406.             }
  1407.         }
  1408.  
  1409.     /* Call internal writeBuffer routine to do the actual write */
  1410.     vwrite( _outBuffer, bufSize );
  1411.     }
  1412.  
  1413. void writeMrglBuffer( const int bufSize )
  1414.     {
  1415.     mrglBufCount = 0;    /* Reset byte counter */
  1416.  
  1417.     /* Call internal writeBuffer routine to do the actual write */
  1418.     vwrite( mrglBuffer, bufSize );
  1419.     }
  1420.  
  1421. void writeDirBuffer( const int bufSize )
  1422.     {
  1423.     int bytesWritten;
  1424.  
  1425.     /* Checksum the data if required.  We don't bother with encryption since
  1426.        eventually this data will be copied to the main archive file, and will
  1427.        be encrypted as it goes through the main buffers */
  1428.     if( doChecksumDirOut )
  1429.         {
  1430.         crc16buffer( dirBuffer + dirChecksumMark, bufSize - dirChecksumMark );
  1431.         dirChecksumMark = 0;
  1432.         }
  1433.  
  1434.     dirBufCount = 0;    /* Reset byte counter */
  1435.     if( ( bytesWritten = hwrite( dirFileFD, dirBuffer, bufSize ) ) == ERROR )
  1436.         fileError();
  1437.     else
  1438.         /* Since the dirBuffer is only ever written to disk we don't need
  1439.            to check for ^Z irregularities under MSDOS */
  1440.         if( bytesWritten != bufSize )
  1441.             error( OUT_OF_DISK_SPACE );
  1442.     }
  1443.  
  1444. /* Flush the output buffers */
  1445.  
  1446. void flushBuffer( void )
  1447.     {
  1448.     int i;
  1449.  
  1450.     if( flags & XLATE_OUTPUT )
  1451.         {
  1452.         /* If we are translating the output, first force the translation of
  1453.            the rest of the output buffer with a call to writeBuffer, and then
  1454.            flush the mrgl buffer if necessary */
  1455.         writeBuffer( _outByteCount );
  1456.         flushMrglBuffer();
  1457.         }
  1458.     else
  1459.         /* Otherwise flush the std.output buffer */
  1460.         if( _outByteCount )
  1461.             {
  1462.             /* Encrypt the data if required */
  1463.             if( doCryptOut )
  1464.                 {
  1465.                 encryptCFB( _outBuffer + cryptMark, _outByteCount - cryptMark );
  1466.                 cryptMark = 0;
  1467.                 }
  1468.  
  1469.             /* Checksum the data if required */
  1470.             if( doChecksumOut )
  1471.                 {
  1472.                 crc16buffer( _outBuffer + checksumMark, _outByteCount - checksumMark );
  1473.                 checksumMark = 0;
  1474.                 }
  1475.  
  1476.             /* If we need to pad the output for a multipart archive, add
  1477.                another MULTIPART_TRAILER_SIZE bytes of data */
  1478.             if( padOutput )
  1479.                 {
  1480.                 for( i = 0; i < MULTIPART_TRAILER_SIZE; i++ )
  1481.                     fputByte( 0 );
  1482.                 outputAdjusted = FALSE;        /* Remember to fiddle things later */
  1483.  
  1484.                 /* Keep calling writeBuffer() until all data is flushed out
  1485.                    of the output buffer (we may need to call writeBuffer()
  1486.                    several times if the data is split over multiple disks) */
  1487.                 while( _outByteCount )
  1488.                     writeBuffer( _outByteCount );
  1489.                 }
  1490.             else
  1491.                 writeBuffer( _outByteCount );
  1492.  
  1493.             /* Adjust data size for padding if it hasn't already been done */
  1494.             if( padOutput && !outputAdjusted )
  1495.                 currLength -= MULTIPART_TRAILER_SIZE;
  1496.             }
  1497.     }
  1498.  
  1499. void flushMrglBuffer( void )
  1500.     {
  1501.     if( mrglBufCount )
  1502.         writeMrglBuffer( mrglBufCount );
  1503.     }
  1504.  
  1505. void flushDirBuffer( void )
  1506.     {
  1507.     if( dirBufCount )
  1508.         writeDirBuffer( dirBufCount );
  1509.     }
  1510.